package multidraw.model.server;

import java.io.File;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

import multidraw.model.Canvas;
import multidraw.model.Shape;
import multidraw.model.TextBox;
import multidraw.model.commands.Command;
import multidraw.model.commands.WrapperCommand;
import multidraw.tools.DynamicToolLoader;
import multidraw.tools.ToolInfo;
import multidraw.util.SyncToolReport;
import multidraw.util.ToolArchive;
import multidraw.util.Zip;

/**
 * This class stores the information a session.
 * @author cuongbk
 *
 */
public class SessionInfo implements Canvas {
	public String sessionID;
	public Hashtable<String, Role> userRoles = new Hashtable<String, Role>();
	public CoreData coreData = new CoreData();
	protected CanvasServer canvasServer;
	protected ArrayList<ToolArchive> toolList = new ArrayList<ToolArchive>();
	protected DynamicToolLoader loader = new DynamicToolLoader();
	
	protected Vector<Class> dynamicClassesList = new Vector<Class>();
	
	//protected Vector<WrapperCommand> changesList = new Vector<WrapperCommand>();
	
	public SessionInfo(String sessionID, CanvasServer server) {
		this.sessionID = sessionID;
		this.canvasServer = server;
	}

	@Override
	public void applyAddShape(Shape s) {
		// TODO Auto-generated method stub
		//coreData.shapes.add(s);
	}

	@Override
	public void applyCommandToCoreData(Command c) {
		// TODO Auto-generated method stub
		coreData.revisionID++;
		c.setCanvas(this);
		c.execute();
	}

	@Override
	public long getNextID() {
//		long id = 1;
//				
//		for (Shape s: coreData.shapes) {
//			if (id < s.getShapeID()) id = s.getShapeID();
//		}
//		
//		return id + 1;
		return -1;
	}

	@Override
	public void applyAddChar(long shapeID, char ch) {
		// TODO Auto-generated method stub
//		for (Shape s: coreData.shapes) {
//			if (s.getShapeID() == shapeID) {
//				TextBox t = (TextBox) s;
//				t.addChar(ch);
//				return;
//			}
//		}
	}

	@Override
	public List<Shape> getShapes() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setSelectedObjectIndex(int index) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void applyAddUser(String name) {
		// TODO Auto-generated method stub
		
	}
	
	public void applyCommand(Command command) {
		// TODO Auto-generated method stub
		//command
		applyCommandToCoreData(command);
		
		//send it to other clients
		Enumeration<String> enu =  userRoles.keys();
		
		while (enu.hasMoreElements()) {
			String o = enu.nextElement();
			ClientInfo clientInfo = canvasServer.getClientInfo(o);
			if (clientInfo != null)
				clientInfo.updates.add(command);			
		}
		
		notifyObservers();
	}
	
	public void notifyObservers() {
		//send it to other clients
		Enumeration<String> enu =  userRoles.keys();
		
		while (enu.hasMoreElements()) {
			String o = enu.nextElement();
			ClientInfo clientInfo = canvasServer.getClientInfo(o);
			if (clientInfo != null) {
				try {
					clientInfo.clientObject.updateModelContent();
				} catch (RemoteException re) {
					System.out.println(re);
				}
			}
		}
	}
	
	public boolean joinClient(String clientID) {
		userRoles.put(clientID, Role.COLLABORATOR);
		notifyObservers();
		return true;
	}
	
	public SyncToolReport syncToolList(ArrayList<ToolInfo> clientList) {
		ArrayList<ToolArchive> serverToolList = new ArrayList<ToolArchive>();
		
		for (ToolArchive t: toolList) {
			if (!clientList.contains(t.toolInfo))
				serverToolList.add(t);
		}
		
		ArrayList<ToolInfo> clientToolList = new ArrayList<ToolInfo>();
		
		for (ToolInfo t: clientList) {
			if (!toolList.contains(t))
				clientToolList.add(t);
		}
		
		SyncToolReport report = new SyncToolReport();
		report.serverNewToolList = serverToolList;
		report.clientNewToolList = clientToolList;
		return report;
	}
	
	public String getSessionID() {
		return sessionID;
	}
	
	public void applyToolList(ArrayList<ToolArchive> toolList) {
		//write to the session folder on the server
		for (ToolArchive ta: toolList) {
			System.out.println("Received the tool " + ta.toolInfo);
			System.out.println("file size: " + ta.data.length);
			//this.toolList.add(ta.toolInfo);
		}
		
		//write to the session folder
		//extract the tools to the sessions/sessionID/tools
		//write to the session folder on the server
		File sessionToolDir = new File(new File("server-sessions", sessionID), loader.loaderID);
		sessionToolDir.mkdirs();
		
		for (ToolArchive ta: toolList) {
			System.out.println("Received the tool " + ta.toolInfo);
			System.out.println("file size: " + ta.data.length);
			
			//extract the data
			try {
				File toolDir = new File(sessionToolDir, ta.toolInfo.toolName);
				Zip.unzipFromByteArray(ta.data, toolDir);
				this.toolList.add(ta);
				
			} catch (Exception e) {
				System.out.println(e);
			}
			
		}
		
		
		Vector<Class> classes = loader.reloadSessionToolList(sessionID);
		dynamicClassesList.addAll(classes);		
	}
	
	public String getOwnerName() {
		return "server";
	}
	
	public void applyWrapperCommand(WrapperCommand cmd) {
		coreData.changesList.add(cmd);
		coreData.revisionID++;
	}
	
	public ArrayList<ClassLoader> getDynamicClassLoaders() {
		return null;
	}
}
